﻿using ClockLib.Logger;
using ClockLib.Audio;

namespace ClockLib
{
    //public class AlarmProgress
    //{
    //    public int TotalSeconds { get; set; }
    //    public int RemainSeconds { get; set; }

    //}
    public class Time
    {
        public int Hour { get; set; }
        public int Minute { get; set; }
    }
 
    public interface IClock
    {
        void RingBell(bool force);
        void ReportTime(int hour, int min, bool force);
        void Run();
        //AlarmProgress GetRemainAlarmSeconds();
        Time GetNextAlarmTime();
        void TestAlarm(int hour,int minute,bool force);
        //void TestAlarm();
    }

    public interface IClockAsync : IClock
    {
        Task RunAsync();
    }
    public class Clock:IClockAsync
    {
        private ClockSettings settings;
        private ILogger? logger=null;
        private DateTime last_report_time;
        private bool stop = false;

        private string bellAudioFilePath = "./media/bell.wav";
        private string reportAudioFolderPath = "./media/report";

        public Clock(ClockSettings settings)
        {
            this.settings = settings;
#if DEBUG
            //this.settings.ReportMinutes.Clear();
            //for (int i = 0; i < 60; i++)
            //{
            //    this.settings.ReportMinutes.Add(i);
            //}
#endif

        }
        public Clock(ClockSettings settings, ILogger logger):this(settings)
        {
            this.logger= logger; 
        }

        public void Stop()
        {
            stop = true;
        }

        public async Task RunAsync()
        {
            RingBell();
            var now = DateTime.Now;
            ReportTime(now.Hour, now.Minute);
            last_report_time = DateTime.Now;

            while (!stop)
            {
                logger?.Debug("Enter check loop...");
                now = DateTime.Now;
                var hour = now.Hour;
                if (settings.SilentHours.Contains(hour))
                {
                    logger?.Debug($"Current Hour[{hour}] is in silent period!");
                    await Task.Delay(1000 * 30);
                    continue;
                }
                var min = now.Minute;
                if (settings.ReportMinutes.Contains(min) && last_report_time.Minute != min)
                {
                    logger?.Debug($"Alarm at {hour}:{min}");
                    RingBell();
                    ReportTime(hour, min);
                    last_report_time = now;
                }
                else
                {
                    logger?.Debug("No need alarming.");
                }
                await Task.Delay(1000*30);
            }
        }

        //private void Alarm(bool force)
        //{
        //    logger?.Debug("Enter check loop...");
        //    var now = DateTime.Now;
        //    var hour = now.Hour;
        //    if (!force && settings.SilentHours.Contains(hour))
        //    {
        //        logger?.Debug($"Current Hour[{hour}] is in silent period!");
        //        return;
        //    }
        //    var min = now.Minute;
        //    if (settings.ReportMinutes.Contains(min) && last_report_time.Minute != min)
        //    {
        //        logger?.Debug($"Alarm at {hour}:{min}");
        //        RingBell();
        //        ReportTime(hour, min);
        //        last_report_time = now;
        //    }
        //    else
        //    {
        //        logger?.Debug("No need alarming.");
        //    }
        //}
        public void Run()
        {

            RunAsync().Wait();
        }
        public void RingBell(bool force=false)
        {
            if (!force&&!settings.EnableBellRing)
            {
                logger?.Debug("Bell ring is disabled!");
                return;
            }
            logger?.Debug("Ring bell!");
            WAVPlayer.QuickPlay(bellAudioFilePath, settings.BellRepeatTime);
        }

        private void ReportHour(WAVPlayer player,int hour)
        {
            var tens = hour / 10;
            var ones= hour % 10;
            if (tens > 1)
            {
                player.Play(Path.Combine(reportAudioFolderPath, $"{tens}.wav"));
            }
            if (tens>0)
            {

            player.Play(Path.Combine(reportAudioFolderPath, "10.wav"));
            }
            if (ones>0)
            {
                player.Play(Path.Combine(reportAudioFolderPath, $"{ones}.wav"));

            }
            player.Play(Path.Combine(reportAudioFolderPath, "dian.wav"));
        }

        private void ReportMinute(WAVPlayer player, int min)
        {
            if (min == 0)
            {
                player.Play(Path.Combine(reportAudioFolderPath, "zheng.wav"));
                return;
            }
            else if (min == 30)
            {
                player.Play(Path.Combine(reportAudioFolderPath, "ban.wav"));
                return;
            }
            else
            {
                var tens = min / 10;
                var ones = min % 10;
                if (tens > 1)
                {
                    player.Play(Path.Combine(reportAudioFolderPath, $"{tens}.wav"));
                }
                if (tens>0)
                {

                player.Play(Path.Combine(reportAudioFolderPath, "10.wav"));
                }
                if (ones > 0)
                {
                    player.Play(Path.Combine(reportAudioFolderPath, $"{ones}.wav"));

                }

            }
            player.Play(Path.Combine(reportAudioFolderPath, "fen.wav"));
        }
        public void ReportTime(int hour, int min,bool force=false)
        {
            if (!force&&!settings.EnableTimeReport)
            {
                logger?.Debug("Time report is disabled!");
                return;
            }
            logger?.Debug("Report Time!");

            var player = new WAVPlayer();
            player.Play(Path.Combine(reportAudioFolderPath,"prefix.wav"));
            ReportHour(player, hour);
            ReportMinute(player, min);            
        }

        public Time GetNextAlarmTime()
        {
            var sorted_minutes = settings.ReportMinutes.OrderBy(n => n);
            var next_minute = sorted_minutes.First();
            foreach (var minute in sorted_minutes)
            {
                if (last_report_time.Minute < minute)
                {
                    next_minute = minute;
                }
            }
            var now = DateTime.Now;
            var hour = now.Hour;
            if (next_minute < now.Minute)
            {
                hour += 1;
            }
            while (settings.SilentHours.Contains(hour))
            {
                hour++;
            }
            //var next_time = new DateTime(
            //    now.Year, now.Month, now.Day, hour, now.Minute, 0);
            //return next_time;
            return new Time
            {
                Hour = hour,
                Minute = next_minute,
            };
        }

        public void TestAlarm(int hour, int minute,bool force)
        {
            if (!force && settings.SilentHours.Contains(hour))
            {
                return;
            }
            RingBell(force);
            ReportTime(hour, minute,force); 
        }

        //public void TestAlarm()
        //{
        //    RingBell(true);
        //    var now = DateTime.Now;
        //    ReportTime(now.Hour, now.Minute, true);
        //}
        //public AlarmProgress GetRemainAlarmSeconds()
        //{
        //    var sorted_minutes = settings.ReportMinutes.OrderBy(n=>n);
        //    var next_minute = sorted_minutes.First();
        //    foreach (var minute in sorted_minutes)
        //    {
        //        if (last_report_time.Minute < minute)
        //        {
        //            next_minute = minute;
        //        }
        //    }
        //    var now = DateTime.Now;
        //    var hour = now.Hour;
        //    if (next_minute<now.Minute)
        //    {
        //        hour += 1;
        //    }
        //    while (settings.SilentHours.Contains(hour))
        //    {
        //        hour++;
        //    }
        //    var next_time = new DateTime(
        //        now.Year, now.Month, now.Day, hour, now.Minute, now.Second);
        //    return new AlarmProgress
        //    {
        //        TotalSeconds = (int)((next_time - last_report_time).TotalSeconds),
        //        RemainSeconds = (int)((next_time - now).TotalSeconds),
        //    };
        //}
    }
}